package main

import (
	"context"
	"encoding/json"
	"fmt"

	//"io"

	"github.com/cloudwebrtc/go-protoo/client"
	"github.com/cloudwebrtc/go-protoo/logger"
	peerLib "github.com/cloudwebrtc/go-protoo/peer"
	"github.com/cloudwebrtc/go-protoo/transport"
	"github.com/pion/webrtc/v2"
)

var (
	useCtx = false
	//api            *webrtc.API
	config webrtc.Configuration
	//peerConnection *webrtc.PeerConnection
	//offer webrtc.SessionDescription

	roomid string = "2233"
	//opusTrack *webrtc.Track
	//vp8Track  *webrtc.Track
	peerId = "ffffffff-d72b-4aac-ba8e-6f4688fb9e30"
	mid    string
	ownMid string

	peer *peerLib.Peer
	//iceCompleteOffer = make(chan bool)

	audioFileName   = "test-pub.ogg"
	videoFileName   = "test-pub.h264"
	codecName       = "h264"
	iceConnectedCtx context.Context
)

func JsonEncode(str string) map[string]interface{} {
	var data map[string]interface{}
	if err := json.Unmarshal([]byte(str), &data); err != nil {
		panic(err)
	}
	return data
}

type AcceptFunc func(data map[string]interface{})
type RejectFunc func(errorCode int, errorReason string)

//var ivfWriter media.

type mSubscribe struct {
	Notification bool   `json:"notification"`
	Method       string `json:"method"`
	Data         mData  `json:"data"`
}

type mData struct {
	Info mInfo  `json:info`
	Mid  string `json:"mid"`
	Rid  string `json:"rid"`
	Uid  string `json:uid`
}

type mInfo struct {
	Name string `json:"name"`
}

type mJsep struct {
	Sdp  string `json:"sdp"`
	Type string `json:"type"`
}

func MapToJson(m map[string]interface{}) (string, error) {
	jsonByte, err := json.Marshal(m)
	if err != nil {
		fmt.Printf("Marshal with error: %+v\n", err)
		return "", nil
	}

	return string(jsonByte), nil
}

//video audio transport

func handleWebSocketOpen(transport *transport.WebSocketTransport) {
	logger.Infof("handleWebSocketOpen")

	peer = peerLib.NewPeer(peerId, transport)

	handleRequest := func(request map[string]interface{}, accept AcceptFunc, reject RejectFunc) {
		method := request["method"]
		logger.Infof("handleRequest =>  (%s) ", method)
		if method == "kick" {
			reject(486, "Busy Here")
		} else {
			accept(JsonEncode(`{}`))
		}
	}

	peer.On("request", handleRequest)
	//peer.On("notification", handleNotification)
	peer.On("close", func(code int, err string) {
		logger.Infof("peer close [%d] %s", code, err)
	})

	join()
	publish()
}

func join() {

	//===============================加入房间=============================================
	mjoin := make(map[string]interface{})
	minfo := make(map[string]interface{})

	mjoin["rid"] = roomid
	mjoin["uid"] = peerId
	minfo["name"] = "guest111"
	mjoin["info"] = minfo
	peer.Request("join", mjoin,
		func(result map[string]interface{}) {
			logger.Infof("join success: =>  %s", result)
		},
		func(code int, err string) {
			logger.Infof("join reject: %d => %s", code, err)
		})
}

func leave() {

}

func publish() {

	offer, _ := pubTrans.pc.CreateOffer(nil)
	pubTrans.pc.SetLocalDescription(offer)

	//=========================================发布===================================================
	mpublish := make(map[string]interface{})
	mpjsep := make(map[string]interface{})
	mpoptions := make(map[string]interface{})
	mpublish["rid"] = roomid
	mpjsep["type"] = webrtc.SDPTypeOffer
	mpjsep["sdp"] = offer.SDP
	mpublish["jsep"] = mpjsep
	mpoptions["audio"] = true
	mpoptions["video"] = true
	mpoptions["screen"] = false
	mpoptions["codec"] = codecName
	mpublish["options"] = mpoptions
	peer.Request("publish", mpublish,
		func(result map[string]interface{}) {
			//logger.Infof("publish success: =>  ")
			logger.Infof("publish success receive jsep: =>  %+v", result["jsep"])

			str, err := json.Marshal(result["jsep"])
			if err != nil {
				fmt.Println(err)
			}
			var myjsep string = string(str)
			//fmt.Println("map to json ", myjsep)
			var xjsep mJsep
			json.Unmarshal([]byte(myjsep), &xjsep)

			err = pubTrans.pc.SetRemoteDescription(webrtc.SessionDescription{ //设置远程描述
				Type: webrtc.SDPTypeAnswer,
				SDP:  xjsep.Sdp,
			})
			if err != nil {
				panic(err)
			}
		},
		func(code int, err string) {
			logger.Infof("publish reject: %d => %s", code, err)
		})
}

func main() {

	initLocal()
	wsClient := client.NewClient("wss://42.194.133.69:8443/ws?peer="+peerId, handleWebSocketOpen)
	wsClient.ReadMessage()
}

func initLocal() {

	pubTrans = NewTrans(true)
	subTrans = NewTrans(true)

	ctx, iceConnectedCtxCancel := context.WithCancel(context.Background())
	iceConnectedCtx = ctx

	pubTrans.writeVideoToTrack(videoFileName)
	pubTrans.writeAudioToTrack(audioFileName)

	pubTrans.pc.OnICEConnectionStateChange(func(connectionState webrtc.ICEConnectionState) { //连接状态已经改变
		logger.Infof("pub Connection State has changed: %s \n", connectionState.String())

		if connectionState == webrtc.ICEConnectionStateChecking {
			logger.Infof(" Connection State is 连接中 \n")
		} else if connectionState == webrtc.ICEConnectionStateConnected {
			logger.Infof("pub Connection State is 连接成功 \n")
			if useCtx {
				iceConnectedCtxCancel()
			} else {
				close(pubTrans.iceConnected)
			}
		} else if connectionState == webrtc.ICEConnectionStateFailed {
			logger.Infof("pub Connection State is 连接失败 \n")
		}
	})

	//offer, _ := pubTrans.pc.CreateOffer(nil)
	//pubTrans.pc.SetLocalDescription(offer)
}
